﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Text.RegularExpressions;

namespace ApiDoc
{
    /// <summary>
    /// Utility methods for HtmlHelper within an Mvc web page.
    /// </summary>
    public static class HtmlHelper_ApiDocumentation
    {
        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, NamespaceDocumentation member)
        {
            return html.ActionLink(linkText, "Namespace", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, NamespaceDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, TypeDocumentation member)
        {
            // Special handling of types that are better linked elsewhere.
            if (member.GenericTypeDefinition != null) {
                // Generic types should link to their definition.
                return html.ActionLink(linkText, "Type", new { id = UrlFriendlyCref(member.GenericTypeDefinition.CRef) });
            } else if (member.ElementType != null) {
                // Types with elements (e.g. arrays) should link to their element type.
                return html.ActionLink(linkText, "Type", new { id = UrlFriendlyCref(member.ElementType.CRef) });
            }

            return html.ActionLink(linkText, "Type", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, TypeDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, MethodDocumentation member)
        {
            return html.ActionLink(linkText, "Method", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, MethodDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, ConstructorDocumentation member)
        {
            return html.ActionLink(linkText, "Constructor", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, ConstructorDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, FieldDocumentation member)
        {
            return html.ActionLink(linkText, "Field", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, FieldDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, PropertyDocumentation member)
        {
            return html.ActionLink(linkText, "Property", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, PropertyDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, EventDocumentation member)
        {
            return html.ActionLink(linkText, "Event", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, EventDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, ParameterDocumentation member)
        {
            return html.ActionLink(linkText, "Parameter", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, ParameterDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, string linkText, AssemblyDocumentation member)
        {
            return html.ActionLink(linkText, "Assembly", new { id = UrlFriendlyCref(member.CRef) });
        }

        public static MvcHtmlString ApiDocumentationLink(this HtmlHelper html, AssemblyDocumentation member)
        {
            return ApiDocumentationLink(html, member.Name, member);
        }

        /// <summary>
        /// Returns a cref suitable for use in an Mvc Applications URL.
        /// </summary>
        /// <param name="cref"></param>
        /// <returns></returns>
        internal static string UrlFriendlyCref(string cref)
        {
            return cref.Replace(".", "-");
        }

        /// <summary>
        /// Returns a HTML version of <paramref name="innerXml"/> with &lt;paramref&gt; etc. replaced with links to the API from the <paramref name="apiBaseUrl"/> calls.
        /// </summary>
        /// <param name="html"></param>
        /// <param name="innerXml"></param>
        /// <returns></returns>
        public static MvcHtmlString ApiDocumentationHtml(MarkupString s, string apiBaseUrl)
        {
            var manager = s.GetManager();
            var member = s.GetOwner();

            string text = manager.CreateDocumentationStringWithLinks(s.ToString(), member);

            // Swap tags to links based on the base URL.
            var matches = Regex.Matches(text, "<link cref=\"([^\"]*)\">([^<]*)</link>")
                .Cast<Match>();
            foreach (var match in matches) {
                text = text.Replace(match.Value, String.Format("<a href=\"{2}/{0}\">{1}</a>", UrlFriendlyCref(match.Groups[1].Value), match.Groups[2].Value, apiBaseUrl));
            }

            return MvcHtmlString.Create(text);
        }
    }
}